package config

import (
	"fmt"
	"sync"

	"context"
	"time"
	"os"
	"github.com/rs/zerolog"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	gormsql "gorm.io/driver/mysql"
	"gorm.io/gorm"
	"github.com/natefinch/lumberjack"
	cron "github.com/robfig/cron/v3"

)


type Config  struct {
	AppName string  `toml:"app_name"`
	*Http  `toml:"http"`
	*Mysql `toml:"mysql"`
	*MongoDb `toml:"mongodb"`
	*Grpc `toml:"grpc"`
	*Logs `toml:"logs"`
	*CrontabStatus  `toml:"crontab"`
}


func (c *Config) String() string { 
	return fmt.Sprintf("AppName: %s \nHttp:%s \nMysql:%s \nMongoDb:%s\nCrontabStatus:%t \n",c.AppName,c.Http,c.Mysql,c.MongoDb,c.CrontabStatus.Enable)
}

func  NewConfigDefault() *Config {
	return &Config{
		AppName: "test",
		Http: NewHttpDefault(),
		Mysql: NewMysqlDefault(),
		MongoDb: NewMongoDbDefault(),
		CrontabStatus: NewDefaultCrontabStatus(),

	}
}

type CrontabStatus  struct{
	Enable  bool  `json:"enable" toml:"enable"`
	Crontab  *cron.Cron  
	Spec  string  `json:"spec" toml:"spec"`
}

func NewDefaultCrontabStatus()  *CrontabStatus{
	return  &CrontabStatus{
		Enable: false,
		Crontab: cron.New(),
	}
}

type Logs  struct{
	LogLevel  string  `json:"loglevel" toml:"loglevel"`
	LogPath  string `json:"logpath" toml:"logpath"`
	MaxSize int `json:"maxsize" toml:"maxsize"`
	MaxBackups int   `json:"maxbackups" toml:"maxbackups"`
	MaxAge int `json:"maxage" toml:"maxage"`
	Logger zerolog.Logger
	FnList  []*os.File
}

func NewDefaultLogs()  *Logs{
	return  &Logs{
		LogLevel: "info",
		LogPath: "./log/",
		FnList: make([]*os.File, 0),
		MaxSize: 10,
		MaxBackups: 3,
		MaxAge: 10,
	}
}


func (l *Logs)  String() string {
	return  fmt.Sprintf("logpath:%s loglevel:%s  maxsize:%d maxbackups:%d maxage:%d\n",l.LogPath,l.LogLevel,l.MaxSize,l.MaxBackups,l.MaxAge)
}


func (l *Logs) Getlog(name string) zerolog.Logger {
	if _, err := os.Stat(l.LogPath); os.IsNotExist(err) {
        os.MkdirAll(l.LogPath, 0644)
    }
	appLog := &lumberjack.Logger{
		Filename:   fmt.Sprintf("%s/%s.log",l.LogPath,name), // 日志文件路径
		MaxSize:    l.MaxSize,                 // 单个日志文件最大大小（以 MB 为单位）
		MaxBackups: l.MaxBackups,                 // 保留旧文件的最大数量
		MaxAge:     l.MaxAge,                 // 旧文件保留的最大天数
		Compress:   true,              // 是否启用压缩
	}
	// l.FnList = append(l.FnList, appLog.)
	if l.LogLevel=="info" {
		l.Logger = zerolog.New(appLog).Level(zerolog.InfoLevel).With().Caller().Timestamp().Logger()
	} else if  l.LogLevel=="warning" {
		l.Logger = zerolog.New(appLog).Level(zerolog.WarnLevel).With().Caller().Timestamp().Logger()
	} else if   l.LogLevel=="error"  {
		l.Logger = zerolog.New(appLog).Level(zerolog.ErrorLevel).With().Caller().Timestamp().Logger()
	}else if   l.LogLevel=="debug"{
		l.Logger = zerolog.New(appLog).Level(zerolog.DebugLevel).With().Caller().Timestamp().Logger()
	}else {
		l.Logger = zerolog.New(appLog).Level(zerolog.InfoLevel).With().Caller().Timestamp().Logger()
	}
	return  l.Logger
}

// 定义web 服务使用的信息
type Http struct {
	Host string `json:"host" toml:"host"`
	Port string  `json:"port" toml:"port"`
}
func NewHttpDefault() *Http {
	return &Http{
		Host: "localhost",
		Port: "8080",
	}
}

func (h *Http) String() string {
	return fmt.Sprintf(h.Host + ":" + h.Port)
}

func (h *Http) GetAddress() string {
	return fmt.Sprintf(h.Host + ":" + h.Port)
}
// 定义Mysql  
type  Mysql struct {
	Host string `json:"host" toml:"host"`
	Port string  `json:"port" toml:"port"`
	UserName string `json:"userName" toml:"userName"`
	Password string `json:"password" toml:"password"`
	DbName string `json:"dbName" toml:"dbName"`
	gormDb  *gorm.DB
	lock  sync.Mutex
}
func (m *Mysql)  String() string{
	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",m.UserName,m.Password,m.Host,m.Port,m.DbName)
}

func NewMysqlDefault() *Mysql {
	return &Mysql{
		Host: "localhost",
		Port: "3306",
		DbName: "test",
		UserName: "admin",
		Password: "123456",
	}
}


type MongoDb struct {
	Host string `json:"host" toml:"host"`
	Port string  `json:"port" toml:"port"`
	UserName string `json:"userName" toml:"userName"`
	Password string `json:"password" toml:"password"`
	Client  *mongo.Client
}

func NewMongoDbDefault() *MongoDb {
	return &MongoDb{
		Host: "localhost",
		Port: "27017",
		UserName: "admin",
		Password: "123456",
	}
}


type Grpc struct{
	Host string `json:"host" toml:"host"`
	Port string  `json:"port" toml:"port"`
}


func NewGrpcDefault() *Grpc {
	return &Grpc{
		Host: "localhost",
		Port: "8090",
	}
}

func (g  *Grpc)String() string {
	return  fmt.Sprintf(g.Host + ":" + g.Port)
}
func (g  *Grpc)GetAddress() string {
	return  fmt.Sprintf(g.Host + ":" + g.Port)
}


func (m *Mysql)  getDsn() string{
	return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",m.UserName,m.Password,m.Host,m.Port,m.DbName)
}
func (m *MongoDb)  getDsn() string{
	return fmt.Sprintf("mongodb://%s:%s",m.Host,m.Port)
}

func (m *MongoDb)  String() string{
	return fmt.Sprintf("mongodb://%s:%s",m.Host,m.Port)
}
func (m *Mysql) GormDB() (*gorm.DB) {
	m.lock.Lock()
	defer  m.lock.Unlock()
	if m.gormDb==nil   {
		db,err:=gorm.Open(gormsql.Open(m.getDsn()), &gorm.Config{})
		if err != nil {
			panic("错误") 
		}
		m.gormDb=db 
		
	}
	return   m.gormDb
}

func (m  *MongoDb)GetMongoDbInit()  (*mongo.Client) {

	clientOptions := options.Client().ApplyURI(m.getDsn())

	// 创建一个新的客户端
	client, err := mongo.Connect(context.Background(), clientOptions)
	if err != nil {
		panic("mongodb get  error")
	}

	// 测试连接
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	err = client.Ping(ctx, nil)
	if err != nil {
		panic("mongodb ping error")
	}
	m.Client=client
	return  m.Client
}